package de.LooLo;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.Toast;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;

/**
 * Activity for MapView of all Loos. The center of the app
 * @author Kevin Seppelt, Lukas Siedel 
 *
 */
public class MapViewActivity extends MapActivity implements LocationListener {

	private MapView mapView;

	private static float lat = 0;
	private static float lon = 0;
	private static double frame_size = 0.5;
	private static double FRAME_SIZE_DB = 1;
	private static double location_change_rate = 250; // in meters

	private MapController mapController;
	private CustomItemizedOverlay itemizedOverlay;
	private ImageButton preferencesButton;
	private ImageButton compassButton;
	private GeoPoint currentPoint;
	private List<Overlay> mapOverlays;
	private CustomItemizedOverlay looOverlay;
	private CustomItemizedOverlay looBuildingOverlay;
	private Drawable currentIcon;
	private Drawable looIcon;
	private Drawable looBuildingIcon;
	private DatabaseManagement dbs = DatabaseManagement.getInstance();
	private boolean inDatabase = false;
	private LooLoader looLoader;
	public Location currentLoc = new Location("Current Position");

	// GPSData gps = GPSData.getInstance();

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.map_view);
		dbs.DataHelper(this);
		if (getCurrentLatitude(this) == 0 && getCurrentLongitude(this) == 0) {
			Toast.makeText(this, "No GPS available!", Toast.LENGTH_SHORT);
		}
		frame_size = Float.valueOf(dbs.selectFirstRange())/1000*2;
		location_change_rate = Float.valueOf(dbs.selectFirstRange())/2;
		currentLoc.setLatitude(getCurrentLatitude(this));
		currentLoc.setLongitude(getCurrentLongitude(this));

		preferencesButton = (ImageButton) findViewById(R.id.showMenuButton);
		compassButton = (ImageButton) findViewById(R.id.compassButton);

		preferencesButton.setOnClickListener(new OnClickListener() {

			public void onClick(View v) {
				Intent uploadIntent = new Intent(MapViewActivity.this,
						LooLoActivity.class);
				startActivity(uploadIntent);
				finish();
			}
		});

		compassButton.setOnClickListener(new OnClickListener() {

			public void onClick(View v) {
				
				Intent uploadIntent = new Intent(MapViewActivity.this,
						CompassActivity.class);
				Location nearest = getNearestToilet();
				uploadIntent.putExtra("lat", nearest.getLatitude());
				uploadIntent.putExtra("lon", nearest.getLongitude());
				startActivity(uploadIntent);
			}

		});
		lat = Float.parseFloat(String.valueOf(getCurrentLatitude(this)));
		lon = Float.parseFloat(String.valueOf(getCurrentLongitude(this)));
		lat = lat * 1000000;
		lon = lon * 1000000;

		mapView = (MapView) findViewById(R.id.map_viewer);
		mapView.setBuiltInZoomControls(true);

		mapOverlays = mapView.getOverlays();
		currentIcon = this.getResources().getDrawable(R.drawable.youarehere);
		looIcon = this.getResources().getDrawable(R.drawable.loo_small_icon);
		looBuildingIcon = this.getResources().getDrawable(
				R.drawable.loobuilding_small_icon);

		itemizedOverlay = new CustomItemizedOverlay(currentIcon, this, 1);
		looOverlay = new CustomItemizedOverlay(looIcon, this, 2);
		looBuildingOverlay = new CustomItemizedOverlay(looBuildingIcon, this, 3);

		currentPoint = new GeoPoint((int) lat, (int) lon);

		ArrayList<Toilet> looList = dbs.selectAllFrameLoos(FRAME_SIZE_DB,
				currentLoc);

		for (int i = 0; i < looList.size(); i++) {

			Toilet loo = looList.get(i);

			float geo_lat = Float.parseFloat(String.valueOf(loo.getLatitude()));
			float geo_long = Float
					.parseFloat(String.valueOf(loo.getLongitude()));

			geo_lat = geo_lat * 1000000;
			geo_long = geo_long * 1000000;

			GeoPoint looPoint = new GeoPoint((int) geo_lat, (int) geo_long);
			OverlayItem looItem = new OverlayItem(looPoint, String.valueOf(loo.getId()), "fee= " + loo.getFee());

			if (loo.insideBuilding) {
				looBuildingOverlay.addOverlay(looItem);
			} else {
				looOverlay.addOverlay(looItem);
			}
		}

		if ((dbs.selectFirstLoc() == null || dbs.selectFirstLoc().distanceTo(
				currentLoc) > location_change_rate)) {
			if (isOnline() && LooGetter.getInstance().getTicketCount() != 0) {

				LooGetter.getInstance().useTaskTicket();
				looLoader = (LooLoader) new LooLoader().execute(
						getCurrentLatitude(this), getCurrentLongitude(this),
						this, frame_size);
				dbs.deleteAllLoc();
				dbs.insertLoc(currentLoc.getLatitude(),
						currentLoc.getLongitude());
			}

		}

		OverlayItem overlayitem = new OverlayItem(currentPoint, "Hello",
				"You are here");
		itemizedOverlay.addOverlay(overlayitem);
		mapOverlays.add(itemizedOverlay);

		if (looOverlay.size() > 0)
			mapOverlays.add(looOverlay);
		if (looBuildingOverlay.size() > 0)
			mapOverlays.add(looBuildingOverlay);

		mapController = mapView.getController();

		mapController.animateTo(currentPoint);
		mapController.setZoom(16);

	}

	/**
	 * Updates Loos
	 * @param lat current lat
	 * @param lon current lon
	 */
	private void updateLooOverlay(double lat, double lon) {
		currentLoc.setLatitude(lat);
		currentLoc.setLongitude(lon);
		ArrayList<Toilet> looListdb = dbs.selectAllFrameLoos(FRAME_SIZE_DB,
				currentLoc);
		for (int i = 0; i < looListdb.size(); i++) {
			Toilet loo = looListdb.get(i);
			float geo_lat = Float.parseFloat(String.valueOf(loo.getLatitude()));
			float geo_long = Float
					.parseFloat(String.valueOf(loo.getLongitude()));

			geo_lat = geo_lat * 1000000;
			geo_long = geo_long * 1000000;

			GeoPoint looPoint = new GeoPoint((int) geo_lat, (int) geo_long);
			OverlayItem looItem = new OverlayItem(looPoint, String.valueOf(loo.getId()), "fee= " + loo.getFee());

			if (loo.insideBuilding) {
				looBuildingOverlay.addOverlay(looItem);
			} else {
				looOverlay.addOverlay(looItem);
			}

		}
		if (looOverlay.size() > 0)
			mapOverlays.add(looOverlay);
		if (looBuildingOverlay.size() > 0)
			mapOverlays.add(looBuildingOverlay);

		mapController.animateTo(currentPoint);

	}

	/*
	 * updates DB and displays toilets, when task is finished
	 */
	public void onLoosChanged() {

		// upgrades the DB
		ArrayList<Toilet> looList = LooGetter.getInstance().getLooList();

		if (looOverlay.size() > 0)
			mapOverlays.remove(mapOverlays.indexOf(looOverlay));
		looOverlay = new CustomItemizedOverlay(looIcon, this, 2);
		if (looBuildingOverlay.size() > 0)
			mapOverlays.remove(mapOverlays.indexOf(looBuildingOverlay));
		looBuildingOverlay = new CustomItemizedOverlay(looBuildingIcon, this, 3);

		for (int i = 0; i < looList.size(); i++) {

			Toilet loo = looList.get(i);

			// proofs if Toilet is already in Database
			for (int j = 0; j < dbs.selectAllLoos().size(); j++) {
				if (dbs.selectAllLoos().get(j).getLatitude() == loo
						.getLatitude()
						&& dbs.selectAllLoos().get(j).getLongitude() == loo
								.getLongitude())
					inDatabase = true;

			}

			if (!inDatabase)
				dbs.insertLoo(loo.getName(), loo.getFee(), loo.getWheelchair(),
						loo.getLayer(), loo.getSupervised(), loo.getLatitude(),
						loo.getLongitude(), loo.getOpening_hours(),
						loo.isInsideBuilding());
			inDatabase = false;


		}
		// updates the Overlay of WC's
		updateLooOverlay(getCurrentLatitude(this), getCurrentLongitude(this));

	}

	@Override
	protected boolean isRouteDisplayed() {
		return false;
	}

	public GeoPoint getCurrentPoint() {
		return currentPoint;
	}

	public void setCurrentPoint(GeoPoint currentPoint) {
		this.currentPoint = currentPoint;
		mapController.animateTo(currentPoint);
		mapOverlays.remove(mapOverlays.indexOf(itemizedOverlay));

		itemizedOverlay = new CustomItemizedOverlay(currentIcon, this, 1);
		OverlayItem overlayitem = new OverlayItem(currentPoint, "Hello",
				"You are here");
		itemizedOverlay.addOverlay(overlayitem);
		mapOverlays.add(itemizedOverlay);
	}

	/*
	 * GPS
	 */

	Location location = null;
	double lat2 = 0;
	double lon2 = 0;
	LocationManager locationManager;
	String context;

	public Location getCurrentLocation(Context mContext) {
		context = Context.LOCATION_SERVICE;
		locationManager = (LocationManager) mContext.getSystemService(context);
		String provider = LocationManager.GPS_PROVIDER;
		locationManager.requestLocationUpdates(provider, 0, 0, this);
		location = locationManager.getLastKnownLocation(provider);

		return location;
	}

	public double getCurrentLatitude(Context mContext) {
		location = getCurrentLocation(mContext);
		if (location == null) {
			return lat2;
		} else
			return location.getLatitude();
	}

	public double getCurrentLongitude(Context mContext) {
		location = getCurrentLocation(mContext);
		if (location == null) {
			return lon2;
		} else
			return location.getLongitude();
	}

	public void onLocationChanged(Location arg0) {
		if (looOverlay.size() > 0)
			mapOverlays.remove(mapOverlays.indexOf(looOverlay));
		looOverlay = new CustomItemizedOverlay(looIcon, this, 2);
		if (looBuildingOverlay.size() > 0)
			mapOverlays.remove(mapOverlays.indexOf(looBuildingOverlay));
		looBuildingOverlay = new CustomItemizedOverlay(looBuildingIcon, this, 3);
		currentLoc.setLatitude(arg0.getLatitude());
		currentLoc.setLongitude(arg0.getLongitude());
		
		
		if ((dbs.selectFirstLoc() == null || dbs.selectFirstLoc().distanceTo(
				currentLoc) > location_change_rate)) {
			if (isOnline() && LooGetter.getInstance().getTicketCount() != 0) {
					
				
				LooGetter.getInstance().useTaskTicket();
				looLoader = (LooLoader) new LooLoader().execute(
						getCurrentLatitude(this), getCurrentLongitude(this),
						this, frame_size);

				dbs.deleteAllLoc();
				dbs.insertLoc(currentLoc.getLatitude(),
						currentLoc.getLongitude());
			}
			
		}
		updateLooOverlay(currentLoc.getLatitude(),
				currentLoc.getLongitude());

		lat2 = arg0.getLatitude();
		lon2 = arg0.getLongitude();
		setCurrentPoint(new GeoPoint(Integer.parseInt(String.valueOf(Math
				.round(lat2 * 1000000))), Integer.parseInt(String.valueOf(Math
				.round(lon2 * 1000000)))));
	}

	public void onProviderDisabled(String provider) {
	}

	public void onProviderEnabled(String provider) {
	}

	public void onStatusChanged(String provider, int status, Bundle extras) {
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		if (isOnline() && LooGetter.getInstance().getTicketCount() == 0)
			looLoader.cancel(true);
	}

	public boolean isOnline() {
		boolean isOnline = false;
		ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
		if (cm.getActiveNetworkInfo() != null)
			isOnline = cm.getActiveNetworkInfo().isConnectedOrConnecting();
		if (!isOnline)
			Toast.makeText(
					getApplicationContext(),
					"No new Toilets could be loaded, because no Internet Connection available",
					Toast.LENGTH_LONG).show();
		return isOnline;
	}

	/**
	 * @return Location of the nearest toilet from current position
	 */
	private Location getNearestToilet() {
		float distance = -1;
		Location nearest = new Location("nearest");
		if(looOverlay.size()>0)
		for (int i = 0; i < looOverlay.size(); i++) {
			Location looLocation = new Location("loo");
			looLocation.setLatitude((double)looOverlay.getItem(i).getPoint()
					.getLatitudeE6() / 1000000);
			looLocation.setLongitude((double)looOverlay.getItem(i).getPoint()
					.getLongitudeE6() / 1000000);
			if (distance == -1
					|| getCurrentLocation(this).distanceTo(looLocation) < distance){
				distance = getCurrentLocation(this).distanceTo(looLocation);
				nearest=looLocation;}
		}
		if(looBuildingOverlay.size()>0)
			for (int i = 0; i < looBuildingOverlay.size(); i++) {
				Location looLocation = new Location("loo");
				looLocation.setLatitude((double)looBuildingOverlay.getItem(i).getPoint()
						.getLatitudeE6() / 1000000);
				looLocation.setLongitude((double)looBuildingOverlay.getItem(i).getPoint()
						.getLongitudeE6() / 1000000);
				if (distance == -1
						|| getCurrentLocation(this).distanceTo(looLocation) < distance){
					distance = getCurrentLocation(this).distanceTo(looLocation);
					nearest=looLocation;}
			}
		return nearest;
	}
	
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.close_menu, menu);
		return true;
	}
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		
		switch (item.getItemId()) {
			
			case R.id.leave_running:
				finish();
				return true;
				
			case R.id.kill:
				System.exit(0);
				return true;
				
			default:
				return true;
				
		}
	}
	@Override
	public void onBackPressed() {
		openOptionsMenu();
	}
}
